package com.gitee.beiding.template_excel_demo;

import com.gitee.beiding.template_excel.Data;
import com.gitee.beiding.template_excel.Renderer;
import com.gitee.beiding.template_excel_demo.entity.Student;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class RenderDemo {

    public static void main(String[] args) throws Exception {


        //准备20个数据实体
        List<Student> students = new ArrayList<>();
        for (int i = 1; i < 21; i++) {
            Student student = new Student();
            student.setName("张伟" + i);

           switch (i % 3) {
                case 0:
                    student.setSubjects(Arrays.asList("桥牌", "电影鉴赏"));
                    student.setIndexs(Arrays.asList(1, 2));
                    break;
                case 1:
                    student.setSubjects(Arrays.asList("围棋", "心理健康"));
                    student.setIndexs(Arrays.asList(1, 2));
                    break;
                case 2:
                    student.setSubjects(Arrays.asList("太极拳", "周易", "中华诗词"));
                    student.setIndexs(Arrays.asList(1, 2, 3));

                    break;
            }

            students.add(student);
        }

        //放入要被渲染的图片

        //模板excel的输入流
        InputStream templateInputStream;

        //渲染结果的输出流
        FileOutputStream resultOutputStream;

        //初次渲染相对耗时较长,因为需要初始化,后面的渲染速度会大幅提升
        for (int i = 1; i < 6; i++) {

            //将数据放入容器中
            Data data = Data.create();
            data.put("students", students);
            data.put("icon", RenderDemo.class.getClassLoader().getResourceAsStream("img.jpg"));


            /*
                本例中使用resources目录下的《模板.xlsx》文件作为渲染模板进行渲染
                渲染表达式说明:
                    1.${xxx}是渲染表达式,在渲染表达式之外的文本将会原样输出.

                    2.如果使用"[index]"作为某个实体的后缀,则表示这个实体是可遍历的,渲染引擎会将其遍历展开
                        例如:表达式"${students[i].name}"中的students实体会被遍历展开,并且将展开的每个实体的name属性填入该单元格

                    3.在同一行中对使用了同名自增变量的多个渲染表达式,其遍历过程是同步的
                        例如:表达式"${students[i].name}"和表达式"${students[i].indexs[j]}"都使用了i作为students的自增变量,因此在这两个单元格展开时使用的是同一个Student实体

                    4.渲染表达式支持多维数组或多层级数组的展开
                        例如:array[i][j]或者students[i].indexs[j]

                      多维数组或多层级数组展开时,引擎将采用字典顺序确定自增变量的层级关系
                        例如:表达式"${students[i].indexs[j]}"中存在i和j两个自增变量,那么在展开时自增变量将采用以下等效的层级关系
                            for(i=0;i<iMax;i++){
                                for(j=0;j<jMax;j++){
                                    ...
                                }
                            }

                      *确定自增变量的层级关系有时也是一件重要的事情,因为这会影响单元格合并情况



                    5.当同一行中渲染表达式渲染的结果存在一对多关系时,引擎会自动将一的那一方进行单元格合并
                        例如:表达式"${students[i].name}"和表达式"${students[i].indexs[j]}"
                            Student实体中name和indexs之间是存在一对多的关系的,因此name会自动单元格合并

                    6.可以采用函数对数据进行操作后再进行遍历输出:
                        例如:表达式"${reversal(students[i].subjects)[j]}"中,reversal就是一个反转函数,该表达式能够叫Student实体中的subjects列表反转后再进行遍历输出(无需担心性能问题,因为reversal函数是带有缓存的. 你也可以使用com.beiding.template-excel.Js.defineFunction函数自定义函数,使用该方法定义的函数都会自带缓存,请不要在方法定义中手动调用_cacheGet和_cachePut,可能会造成无限递归问题)


                    7.picture是一个特殊的函数,它可以将byte[] 转换为图片进行输出



               指令函数说明:  1. 由于无法在数据展开的过程中确定数据行的索引,因此对于依赖数据行索引生成的数据就无法使用渲染表达式生成,指令函数提供一种方式在数据填充进单元格时生成所需的数据

                            2. 格式为"$xxx(xx)",例如"$index(from)"

                            3. 你可以使用com.beiding.template-excel.Js.defineCommand定义一个指令函数.
                                    例如:
                                        Js.defineCommand("function $test(){return "测试"}")

                               指令定义中,你可以引用"_index",这是一个以模板行为单位的索引引用,从0开始自增模板行展开的行数
                                    例如:一个模板行展开了20行,index会从0开始自增到19

                               你也可以引用_globalIndex,这是从0开始的当前Sheet页的全局行号引用

                                _col是当前列的列号,从0开始

                        *注意:指令函数不要写在渲染表达式中





             */
            templateInputStream = RenderDemo.class.getClassLoader().getResourceAsStream("模板.xlsx");
            /*
                本例中生成临时文件作为渲染结果的输出
             */
            File tempFile = File.createTempFile("template-excel-demo-", ".xlsx");
            System.out.println("第" + i + "次文件输出路径:" + tempFile.getAbsolutePath());
            resultOutputStream = new FileOutputStream(tempFile);
            long start = System.currentTimeMillis();
            Renderer.render(data,
                    templateInputStream,
                    resultOutputStream);
            System.out.println("第" + i + "次渲染总耗时:" + (System.currentTimeMillis() - start) + "ms");
            resultOutputStream.close();
        }
    }

}
